home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / utilities / printer / post-1.6src.lzh / postdraw.c < prev    next >
C/C++ Source or Header  |  1991-04-19  |  58KB  |  1,720 lines

  1. /* PostScript interpreter file "postdraw.c" - path fill and images */
  2. /* (C) Adrian Aylward 1989, 1991 */
  3.  
  4. # include "post.h"
  5.  
  6. /* Routines */
  7.  
  8. extern void fillslow(int yy, int y2, int rule);
  9. extern void fillfast(int yy, int y2, int rule);
  10. extern void fillline(struct point *ppoint, int cdir, int fdir);
  11. extern void fillxyxy(double *xy1, double *xy2, int cdir, int fdir);
  12. extern void imageslow(int xpos1, int ypos1, int xpos2, int ypos2);
  13. extern void imagefast(int xpos1, int ypos1, int blen);
  14.  
  15. /* Set up the halftone screens before filling a path */
  16.  
  17. void setupfill(void)
  18. {   if (istate.flags & intgraph) error(errundefined);
  19.  
  20.     if (halfok > gnest) setuphalf();
  21.  
  22.     if (gstate.shadeok == 0) setupshade();
  23.  
  24.     if (screenok == 0)
  25.     {   setupscreen(gstate.shade);
  26.         screenok = 1;
  27.     }
  28. }
  29.  
  30. /* Fill a path */
  31.  
  32. void fill(int beg, int end, int rule)
  33. {   struct point *ppoint;
  34.     int count, y2, y1;
  35.  
  36.     /* Set up the fill and clip lines.  Clipping in the x direction merely
  37.      * prevents integer overflow.  Clipping in the y direction minimises the
  38.      * number of scan lines we need to process.  We clip the fill path first,
  39.      * using the fixed limits.  Then we clip the clipping path, using the
  40.      * minimum and maximum y values from the fill path.  This optimises the
  41.      * common case where the fill path fits entirely within the clip path.
  42.      * We can't clip to the exact page width in the x direction, as we always
  43.      * draw the line widths, so we could get spurious lines along the left
  44.      * or right edges.  In the y direction we clip to the exact page size;
  45.      * we assume that integers are represented exactly in floating point */
  46.  
  47.     ymax = ylwb = gstate.dev.ybase * 256.0;
  48.     ymin = yupb = (gstate.dev.ybase + gstate.dev.ysize) * 256.0;
  49.     lineend = 0;
  50.     count = end - beg;
  51.     ppoint = &patharray[beg];
  52.     while (count--)
  53.     {   if (ppoint->type != ptmove) fillline(ppoint - 1, 0, 1);
  54.         ppoint++;
  55.     }
  56.     if (lineend == 0) return;
  57.  
  58.     /* Determine the vertical limits of the fill */
  59.  
  60.     y1 = ((int) ymin) >> 8;
  61.     y2 = (((int) ymax) >> 8) + 1;
  62.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  63.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  64.  
  65.     /* Only process the clip lines if we have a non-standard clip path */
  66.  
  67.     if (gstate.clipflag)
  68.     {   ylwb = y1 * 256.0;
  69.         yupb = y2 * 256.0;
  70.         count = gstate.pathbeg - gstate.clipbeg;
  71.         ppoint = &patharray[gstate.clipbeg];
  72.         while (count--)
  73.         {   if (ppoint->type != ptmove) fillline(ppoint - 1, 1, 0);
  74.             ppoint++;
  75.         }
  76.     }
  77.  
  78.     /* Set up the y buckets, and do the fill */
  79.  
  80.     setybucket(gstate.dev.ybase, gstate.dev.ysize);
  81.     if (gstate.clipflag)
  82.         fillslow(y1, y2, rule);
  83.     else
  84.         fillfast(y1, y2, rule);
  85.     ybflag = 0;
  86.  
  87.     flushlpage(y1, y2);
  88. }
  89.  
  90. /* Slow fill, has to handle clip lines too */
  91.  
  92. void fillslow(int yy, int y2, int rule)
  93. {   struct line *pline, **ppline;
  94.     struct lineseg lineseg, *plineseg;
  95.     struct halfscreen *hscreen;
  96.     struct halftone *htone;
  97.     char *dptr1, *dptr2;        /* device buffer pointers */
  98.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  99.     int flag, count, segments;  /* in-out flag, counter, segments */
  100.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  101.     int x1, x2, xp, xx;         /* current, previous x position range */
  102.     int cdir, fdir, sdir;       /* clip, fill direction counters */
  103.     int poff;                   /* offset of line from page */
  104.     int xmod, hxsize;           /* position modulo halftone screen */
  105.     int mask1, mask2;           /* bit masks for first and last bytes */
  106.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  107.     int plane;
  108.  
  109.     /* Fill the area.  Start at the lowest scan line in the path and loop
  110.      * until we reach the highest */
  111.  
  112.     active = discard = sort = 0;
  113.     poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  114.  
  115.     while (yy < y2)
  116.     {
  117.         /* Add all the new lines */
  118.  
  119.         pline = ybucket[yy - gstate.dev.ybase];
  120.         ybucket[yy - gstate.dev.ybase] = NULL;
  121.         while (pline)
  122.         {   lineptr[active++] = pline;
  123.             pline = pline->chain;
  124.             sort++;
  125.         }
  126.  
  127.         /* If we have any lines out of order or (new, being discarded) then
  128.          * we Shell sort the lines according to their current x coordinates.
  129.          * Any previously finished lines have large x coordinates so will be
  130.          * moved to the end of the array where they are discarded */
  131.  
  132.         sort += discard;
  133.         if (sort != 0)
  134.         {   count = active;
  135.             for (;;)
  136.             {   count = count / 3 + 1;
  137.                 for (x1 = count; x1 < active; x1++)
  138.                     for (x2 = x1 - count;
  139.                          x2 >= 0 &&
  140.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  141.                          x2 -= count)
  142.                     {   pline = lineptr[x2];
  143.                         lineptr[x2] = lineptr[x2 + count];
  144.                         lineptr[x2 + count] = pline;
  145.                     }
  146.                 if (count == 1) break;
  147.             }
  148.             active -= discard;
  149.             discard = sort = 0;
  150.         }
  151.  
  152.         /* Scan convert the scan line */
  153.  
  154.         count = active;
  155.         cdir = fdir = 0;
  156.         ppline = &lineptr[0];
  157.         plineseg = linesegarray;
  158.         segments = 0;
  159.         xp = -32767;
  160.  
  161.         while (count--)
  162.         {   pline = *ppline++;
  163.             x1 = pline->xx >> 16;
  164.  
  165.             /* At the end of the line (or if it is horizontal), use the
  166.              * special value of the x increment.  Flag it to be discarded.
  167.              * Draw only its width. We build a list of line segments to be
  168.              * drawn, creating entries for both the line width itself and
  169.              * (when we are not at the end) the area enclosed.  (Score
  170.              * 1 for the beginning of segment and -1 for the end */
  171.  
  172.             if (yy == pline->y2)
  173.             {   pline->xx += pline->d2;
  174.                 x2 = pline->xx >> 16;
  175.                 pline->xx = 0x7fffffff;
  176.                 discard++;
  177.                 if (x2 < x1)
  178.                 {   xx = x1;
  179.                     x1 = x2;
  180.                     x2 = xx;
  181.                 }
  182.                 x2++;
  183.  
  184.                 if (pline->cdir != 0)
  185.                 {   lineseg.fdir = 0;
  186.                     lineseg.cdir =  1;
  187.                     lineseg.x = x1;
  188.                     *plineseg++ = lineseg;
  189.                     lineseg.cdir = -1;
  190.                     lineseg.x = x2;
  191.                     *plineseg++ = lineseg;
  192.                     segments += 2;
  193.                 }
  194.                 else
  195.                 {   lineseg.cdir = 0;
  196.                     lineseg.fdir =  1;
  197.                     lineseg.x = x1;
  198.                     *plineseg++ = lineseg;
  199.                     lineseg.fdir = -1;
  200.                     lineseg.x = x2;
  201.                     *plineseg++ = lineseg;
  202.                     segments += 2;
  203.                 }
  204.             }
  205.  
  206.             /* At the beginning of the line, use the special values of the
  207.              * x increment; otherwise add the gradient to its current x
  208.              * coordinate.  We have to draw both the lines widths and the
  209.              * area enclosed.  Build the segment list; if two endpoints are
  210.              * coincident add the scores.  For left edges we start drawing
  211.              * at the left of the line and draw the width too; for right
  212.              * edges we stop drawing at the right of the line. For interior
  213.              * lines we draw the line width (as it may not be interior
  214.              * higher up in the pixel */
  215.  
  216.             else
  217.             {   if      (yy == pline->y1)
  218.                     pline->xx += pline->d1;  /* Beginning */
  219.                 else
  220.                     pline->xx += pline->dx;  /* Middle */
  221.                 x2 = pline->xx >> 16;
  222.                 if (x2 < xp) sort++;
  223.                 xp = x2;
  224.                 if (x2 < x1)
  225.                 {   xx = x1;
  226.                     x1 = x2;
  227.                     x2 = xx;
  228.                 }
  229.                 x2++;
  230.  
  231.                 if (pline->cdir != 0)
  232.                 {   lineseg.fdir = 0;
  233.                     sdir = cdir;
  234.                     cdir += pline->cdir;
  235.                     if      ((sdir & rule) == 0) /* Left edge */
  236.                     {   lineseg.cdir =  2;
  237.                         lineseg.x = x1;
  238.                         *plineseg++ = lineseg;
  239.                         lineseg.cdir = -1;
  240.                         lineseg.x = x2;
  241.                         *plineseg++ = lineseg;
  242.                         segments += 2;
  243.                     }
  244.                     else if ((cdir & rule) == 0) /* Right edge */
  245.                     {   lineseg.cdir = -1;
  246.                         lineseg.x = x2;
  247.                         *plineseg++ = lineseg;
  248.                         segments += 1;
  249.                     }
  250.                     else if (x1 != x2)           /* Interior, draw width */
  251.                     {   lineseg.cdir =  1;
  252.                         lineseg.x = x1;
  253.                         *plineseg++ = lineseg;
  254.                         lineseg.cdir = -1;
  255.                         lineseg.x = x2;
  256.                         *plineseg++ = lineseg;
  257.                         segments += 2;
  258.                     }
  259.                 }
  260.                 else
  261.                 {   lineseg.cdir = 0;
  262.                     sdir = fdir;
  263.                     fdir += pline->fdir;
  264.                     if      ((sdir & rule) == 0) /* Left edge */
  265.                     {   lineseg.fdir =  2;
  266.                         lineseg.x = x1;
  267.                         *plineseg++ = lineseg;
  268.                         lineseg.fdir = -1;
  269.                         lineseg.x = x2;
  270.                         *plineseg++ = lineseg;
  271.                         segments += 2;
  272.                     }
  273.                     else if ((fdir & rule) == 0) /* Right edge */
  274.                     {   lineseg.fdir = -1;
  275.                         lineseg.x = x2;
  276.                         *plineseg++ = lineseg;
  277.                         segments += 1;
  278.                     }
  279.                     else if (x1 != x2)           /* Interior, draw width */
  280.                     {   lineseg.fdir =  1;
  281.                         lineseg.x = x1;
  282.                         *plineseg++ = lineseg;
  283.                         lineseg.fdir = -1;
  284.                         lineseg.x = x2;
  285.                         *plineseg++ = lineseg;
  286.                         segments += 2;
  287.                     }
  288.                 }
  289.             }
  290.         }
  291.  
  292.         /* Sort the line segment list.  It should be almost in order, so
  293.          * a simple sort is probably optimal */
  294.  
  295.         xx = 0;
  296.         while (xx < segments - 1)
  297.         {   flag = 0;
  298.             count = segments - 1 - xx;
  299.             plineseg = linesegarray;
  300.             while (count--)
  301.             {   if (plineseg->x > (plineseg + 1)->x)
  302.                 {   flag = 1;
  303.                     lineseg = *plineseg;
  304.                     *plineseg = *(plineseg + 1);
  305.                     *(plineseg + 1) = lineseg;
  306.                 }
  307.                 plineseg++;
  308.             }
  309.             if (flag == 0) break;
  310.             xx++;
  311.         }
  312.  
  313.         /* Scan the list, drawing line segments as we find them */
  314.  
  315.         flag = 0;
  316.         cdir = fdir = 0;
  317.         for (plineseg = linesegarray; segments--; plineseg++)
  318.         {   cdir += plineseg->cdir;
  319.             fdir += plineseg->fdir;
  320.             if (flag == 0)
  321.             {   if (cdir && fdir)
  322.                 {   flag = 1;
  323.                     x1 = plineseg->x;
  324.                 }
  325.                 continue;
  326.             }
  327.             else
  328.             {   if (cdir && fdir)
  329.                     continue;
  330.                 else
  331.                 {   flag = 0;
  332.                     x2 = plineseg->x;
  333.                 }
  334.             }
  335.             if (x1 < 0) x1 = 0;
  336.             if (x2 > gstate.dev.xsize) x2 = gstate.dev.xsize;
  337.             if (x1 >= x2) continue;
  338.  
  339.             /* Draw from x1 to x2 */
  340.  
  341.             xbyt1 = x1 >> 3;
  342.             xbyt2 = (x2 - 1) >> 3;
  343.             mask1 =  0xff >> (x1 & 7);
  344.             mask2 = ~0xff >> (((x2 - 1) & 7) + 1);
  345.  
  346.             /* Loop through the bit planes */
  347.  
  348.             hscreen = &halfscreen[0];
  349.             for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  350.             {   htone = hscreen->halftone;
  351.                 dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  352.                 dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  353.  
  354.                 /* Optimise black or white */
  355.  
  356.                 if      (hscreen->num == 0)
  357.                 {   if (dptr1 == dptr2)
  358.                         *dptr1 |= (mask1 & mask2);
  359.                     else
  360.                     {   *dptr1++ |= mask1;
  361.                         while (dptr1 != dptr2) *dptr1++ = 0xff;
  362.                         *dptr1 |= mask2;
  363.                     }
  364.                 }
  365.                 else if (hscreen->num == htone->area)
  366.                 {   if (dptr1 == dptr2)
  367.                         *dptr1 &= ~(mask1 & mask2);
  368.                     else
  369.                     {   *dptr1++ &= ~mask1;
  370.                         while (dptr1 != dptr2) *dptr1++ = 0x00;
  371.                         *dptr1 &= ~mask2;
  372.                     }
  373.                 }
  374.  
  375.                 /* The general case needs a halftone screen */
  376.  
  377.                 else
  378.                 {   xmod = xbyt1 % htone->xsize;
  379.                     hbeg = hscreen->ptr +
  380.                         (yy % htone->ysize) * htone->xsize;
  381.                     hptr = hbeg + xmod;
  382.                     hxsize = htone->xsize;
  383.                     if (dptr1 == dptr2)
  384.                     {   mask1 &= mask2;
  385.                         *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  386.                     }
  387.                     else
  388.                     {   *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  389.                         dptr1++;
  390.                         hptr++;
  391.                         for (;;)
  392.                         {   xmod++;
  393.                             if (xmod == hxsize)
  394.                             {   xmod = 0;
  395.                                 hptr = hbeg;
  396.                             }
  397.                             if (dptr1 == dptr2) break;
  398.                             *dptr1++ = *hptr++;
  399.                         }
  400.                         *dptr1 = (*dptr1 & ~mask2) | (*hptr & mask2);
  401.                     }
  402.                 }
  403.             }
  404.         }
  405.  
  406.         /* Continue with the next scan line */
  407.  
  408.         poff += gstate.dev.xbytes;
  409.         yy++;
  410.     }
  411. }
  412.  
  413. /* Fast fill a path, no clipping needed */
  414.  
  415. void fillfast(int yy, int y2, int rule)
  416. {   struct line *pline, **ppline;
  417.     struct halfscreen *hscreen;
  418.     struct halftone *htone;
  419.     char *dptr1, *dptr2;        /* device buffer pointers */
  420.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  421.     int count;                  /* counter */
  422.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  423.     int x1, x2, xp, xx;         /* current, previous x position range */
  424.     int fdir;                   /* fill direction counter */
  425.     int poff;                   /* offset of line from page */
  426.     int xmod, hxsize;           /* position modulo halftone screen */
  427.     int mask1, mask2;           /* bit masks for first and last bytes */
  428.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  429.     int s1, s2;                 /* segment to draw */
  430.     int plane;
  431.  
  432.     /* Fill the area.  Start at the lowest scan line in the path and loop
  433.      * until we reach the highest */
  434.  
  435.     active = discard = sort = 0;
  436.     poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  437.  
  438.     while (yy < y2)
  439.     {
  440.         /* Add all the new lines */
  441.  
  442.         pline = ybucket[yy - gstate.dev.ybase];
  443.         ybucket[yy - gstate.dev.ybase] = NULL;
  444.         while (pline)
  445.         {   lineptr[active++] = pline;
  446.             pline = pline->chain;
  447.             sort++;
  448.         }
  449.  
  450.         /* If we have any lines out of order or (new, being discarded) then
  451.          * we Shell sort the lines according to their current x coordinates.
  452.          * Any previously finished lines have large x coordinates so will be
  453.          * moved to the end of the array where they are discarded */
  454.  
  455.         sort += discard;
  456.         if (sort != 0)
  457.         {   count = active;
  458.             for (;;)
  459.             {   count = count / 3 + 1;
  460.                 for (x1 = count; x1 < active; x1++)
  461.                     for (x2 = x1 - count;
  462.                          x2 >= 0 &&
  463.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  464.                          x2 -= count)
  465.                     {   pline = lineptr[x2];
  466.                         lineptr[x2] = lineptr[x2 + count];
  467.                         lineptr[x2 + count] = pline;
  468.                     }
  469.                 if (count == 1) break;
  470.             }
  471.             active -= discard;
  472.             discard = sort = 0;
  473.         }
  474.  
  475.         /* Scan convert the scan line */
  476.  
  477.         count = active;
  478.         fdir = 0;
  479.         ppline = &lineptr[0];
  480.         xp = -32767;
  481.  
  482.         while (count--)
  483.         {   pline = *ppline++;
  484.             x1 = pline->xx >> 16;
  485.  
  486.             /* At the end of the line (or if it is horizontal), use the
  487.              * special value of the x increment.  Flag it to be discarded.
  488.              * Draw only its width */
  489.  
  490.             if (yy == pline->y2)
  491.             {   pline->xx += pline->d2;
  492.                 x2 = pline->xx >> 16;
  493.                 pline->xx = 0x7fffffff;
  494.                 discard++;
  495.                 if (x2 < x1)
  496.                 {   xx = x1;
  497.                     x1 = x2;
  498.                     x2 = xx;
  499.                 }
  500.                 if ((fdir & rule) == 0)
  501.                 {   s1 = x1;
  502.                     s2 = x2;
  503.                 }
  504.                 else
  505.                 {   if (x1 < s1) s1 = x1;
  506.                     if (x2 > s2) s2 = x2;
  507.                     continue;
  508.                 }
  509.             }
  510.  
  511.             /* At the beginning of the line, use the special value of the
  512.              * x increment; otherwise add the gradient to its current x
  513.              * coordinate.  We have to draw both the lines widths and the
  514.              * area enclosed.  For left edges we start drawing at the left
  515.              * of the line and draw the width too; for right edges we stop
  516.              * drawing at the right of the line. For interior lines we draw
  517.              * the line width (as it may not be interior higher up in the
  518.              * pixel */
  519.  
  520.             else
  521.             {   if      (yy == pline->y1)
  522.                     pline->xx += pline->d1;  /* Beginning */
  523.                 else
  524.                     pline->xx += pline->dx;  /* Middle */
  525.                 x2 = pline->xx >> 16;
  526.                 if (x2 < xp) sort++;
  527.                 xp = x2;
  528.                 if (x2 < x1)
  529.                 {   xx = x1;
  530.                     x1 = x2;
  531.                     x2 = xx;
  532.                 }
  533.                 if      ((fdir & rule) == 0) /* Left edge */
  534.                 {   fdir += pline->fdir;
  535.                     s1 = x1;
  536.                     s2 = x2;
  537.                     continue;
  538.                 }
  539.                 if (x1 < s1) s1 = x1;        /* Right edge, or ... */
  540.                 if (x2 > s2) s2 = x2;
  541.                 fdir += pline->fdir;
  542.                 if      ((fdir & rule) != 0) /* Interior */
  543.                     continue;
  544.             }
  545.  
  546.             /* Draw from s1 to s2 */
  547.  
  548.             s2++;
  549.             if (s1 < 0) s1 = 0;
  550.             if (s2 > gstate.dev.xsize) s2 = gstate.dev.xsize;
  551.             if (s1 >= s2) continue;
  552.             xbyt1 = s1 >> 3;
  553.             xbyt2 = (s2 - 1) >> 3;
  554.             mask1 =  0xff >> (s1 & 7);
  555.             mask2 = ~0xff >> (((s2 - 1) & 7) + 1);
  556.  
  557.             /* Loop through the bit planes */
  558.  
  559.             hscreen = &halfscreen[0];
  560.             for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  561.             {   htone = hscreen->halftone;
  562.                 dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  563.                 dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  564.  
  565.                 /* Optimise black or white */
  566.  
  567.                 if      (hscreen->num == 0)
  568.                 {   if (dptr1 == dptr2)
  569.                         *dptr1 |= (mask1 & mask2);
  570.                     else
  571.                     {   *dptr1++ |= mask1;
  572.                         while (dptr1 != dptr2) *dptr1++ = 0xff;
  573.                         *dptr1 |= mask2;
  574.                     }
  575.                 }
  576.                 else if (hscreen->num == htone->area)
  577.                 {   if (dptr1 == dptr2)
  578.                         *dptr1 &= ~(mask1 & mask2);
  579.                     else
  580.                     {   *dptr1++ &= ~mask1;
  581.                         while (dptr1 != dptr2) *dptr1++ = 0x00;
  582.                         *dptr1 &= ~mask2;
  583.                     }
  584.                 }
  585.  
  586.                 /* The general case needs a halftone screen */
  587.  
  588.                 else
  589.                 {   xmod = xbyt1 % htone->xsize;
  590.                     hbeg = hscreen->ptr +
  591.                         (yy % htone->ysize) * htone->xsize;
  592.                     hptr = hbeg + xmod;
  593.                     hxsize = htone->xsize;
  594.                     if (dptr1 == dptr2)
  595.                     {   mask1 &= mask2;
  596.                         *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  597.                     }
  598.                     else
  599.                     {   *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  600.                         dptr1++;
  601.                         hptr++;
  602.                         for (;;)
  603.                         {   xmod++;
  604.                             if (xmod == hxsize)
  605.                             {   xmod = 0;
  606.                                 hptr = hbeg;
  607.                             }
  608.                             if (dptr1 == dptr2) break;
  609.                             *dptr1++ = *hptr++;
  610.                         }
  611.                         *dptr1 = (*dptr1 & ~mask2) | (*hptr & mask2);
  612.                     }
  613.                 }
  614.             }
  615.         }
  616.  
  617.         /* Continue with the next scan line */
  618.  
  619.         poff += gstate.dev.xbytes;
  620.         yy++;
  621.     }
  622. }
  623.  
  624. /* Clip a line and scale it ready for filling */
  625.  
  626. void fillline(struct point *ppoint, int cdir, int fdir)
  627. {   double xy1[2], xy2[2];
  628.  
  629.     /* We convert the coordinates to fixed point, with a scale factor of
  630.      * 256.  Then when it comes to calculating the gradients it will all
  631.      * fit into 32 bits without overflow */
  632.  
  633.     xy1[0] = floor(ppoint[0].x * 256.0 + 0.5);
  634.     xy1[1] = floor(ppoint[0].y * 256.0 + 0.5);
  635.     xy2[0] = floor(ppoint[1].x * 256.0 + 0.5);
  636.     xy2[1] = floor(ppoint[1].y * 256.0 + 0.5);
  637.     
  638.     /* Make y1 <= y2 */
  639.  
  640.     if (xy1[1] < xy2[1])
  641.         fillxyxy(xy1, xy2,  cdir,  fdir);
  642.     else
  643.         fillxyxy(xy2, xy1, -cdir, -fdir);
  644. }
  645.  
  646.  
  647. /* Clip a line and insert it into its y bucket list ready for filling */
  648.  
  649. void fillxyxy(double *xy1, double *xy2, int cdir, int fdir)
  650. {   struct line line;
  651.     double x1, y1, x2, y2, yy;
  652.  
  653.     x1 = xy1[0];
  654.     y1 = xy1[1];
  655.     x2 = xy2[0];
  656.     y2 = xy2[1];
  657.  
  658.     /* Clip to the bottom and top.  Parts off the bottom or top are discarded
  659.      */
  660.  
  661.     if (y1 < ylwb)
  662.     {   if (y2 < ylwb) return;
  663.         x1 = floor(x1 - (y1 - ylwb) * (x2 - x1) / (y2 - y1) + 0.5);
  664.         y1 = ylwb;
  665.     }
  666.     if (y2 > yupb)
  667.     {   if (y1 > yupb) return;
  668.         x2 = floor(x2 - (y2 - yupb) * (x2 - x1) / (y2 - y1) + 0.5);
  669.         y2 = yupb;
  670.     }
  671.     if (y1 < ymin) ymin = y1;
  672.     if (y2 > ymax) ymax = y2;
  673.  
  674.     /* Clip to the left and right.  Parts off the edges are converted to
  675.      * vertical lines along the edges */
  676.  
  677.     if (x1 < xlwb)
  678.         if (x2 < xlwb)
  679.             x1 = x2 = xlwb;
  680.         else
  681.         {   yy = floor(y1 - (x1 - xlwb) * (y2 - y1) / (x2 - x1) + 0.5);
  682.             if (yy > y1 && yy < y2)
  683.             {   xy1[0] = xlwb;
  684.                 xy1[1] = y1;
  685.                 xy2[0] = xlwb;
  686.                 xy2[1] = yy;
  687.                 fillxyxy(xy1, xy2, cdir, fdir);
  688.                 y1 = yy;
  689.             }
  690.             x1 = xlwb;
  691.         }
  692.     else
  693.         if (x2 < xlwb)
  694.         {   yy = floor(y2 - (x2 - xlwb) * (y1 - y2) / (x1 - x2) + 0.5);
  695.             if (yy > y1 && yy < y2)
  696.             {   xy1[0] = xlwb;
  697.                 xy1[1] = yy;
  698.                 xy2[0] = xlwb;
  699.                 xy2[1] = y2;
  700.                 fillxyxy(xy1, xy2, cdir, fdir);
  701.                 y2 = yy;
  702.             }
  703.             x2 = xlwb;
  704.         }
  705.     if (x1 > xupb)
  706.         if (x2 > xupb)
  707.             x1 = x2 = xupb;
  708.         else
  709.         {   yy = floor(y1 - (x1 - xupb) * (y1 - y2) / (x1 - x2) + 0.5);
  710.             if (yy > y1 && yy < y2)
  711.             {   xy1[0] = xupb;
  712.                 xy1[1] = y1;
  713.                 xy2[0] = xupb;
  714.                 xy2[1] = yy;
  715.                 fillxyxy(xy1, xy2, cdir, fdir);
  716.                 y1 = yy;
  717.             }
  718.             x1 = xupb;
  719.         }
  720.     else
  721.         if (x2 > xupb)
  722.         {   yy = floor(y2 - (x2 - xupb) * (y2 - y1) / (x2 - x1) + 0.5);
  723.             if (yy > y1 && yy < y2)
  724.             {   xy1[0] = xupb;
  725.                 xy1[1] = yy;
  726.                 xy2[0] = xupb;
  727.                 xy2[1] = y2;
  728.                 fillxyxy(xy1, xy2, cdir, fdir);
  729.                 y2 = yy;
  730.             }
  731.             x2 = xupb;
  732.         }
  733.  
  734.     /* The top edge is just outside the page */
  735.  
  736.     if (y1 >= yupb) return;
  737.  
  738.     /* Construct the line.  If it is not horizontal calculate the gradient
  739.      * and the special values of the x displacement for the first and last
  740.      * lines.  The x coordinates are on a scale of 65536  */
  741.  
  742.     line.cdir = cdir;
  743.     line.fdir = fdir;
  744.     line.xx = x1 * 256.0;
  745.     line.y1 = ((int) y1) / 256;
  746.     line.y2 = ((int) y2) / 256;
  747.     if (line.y2 == line.y1)
  748.     {   line.dx = 0;
  749.         line.d1 = 0;
  750.         line.d2 = (x2 - x1) * 256.0;
  751.     }
  752.     else
  753.     {   yy = (x2 - x1) / (y2 - y1) * 256.0;
  754.         line.dx = yy * 256.0;
  755.         line.d1 = ((line.y1 + 1) * 256.0 - y1) * yy;
  756.         line.d2 = (y2 - line.y2 * 256.0) * yy;
  757.     }
  758.  
  759.     /* Store the line in the line array */
  760.  
  761.     checklinesize(lineend + 1);
  762.     linearray[lineend++] = line;
  763.  
  764. }
  765.  
  766. /* Set up the y bucket list */
  767.  
  768. void setybucket(int base, int size)
  769. {   struct line *pline;
  770.     int len, i;
  771.  
  772.     len = size * sizeof (struct line *);
  773.     if (len > memylen)
  774.     {   memfree(memybeg, memylen);
  775.         memylen = 0;
  776.         memybeg = memalloc(len);
  777.         if (memybeg == NULL) error(errmemoryallocation);
  778.         memylen = len;
  779.         ybucket = memybeg;
  780.     }
  781.     else
  782.         if (ybflag) memset((char *) memybeg, 0, memylen);
  783.     ybflag = 1;
  784.  
  785.     pline = &linearray[0];
  786.     i = lineend;
  787.  
  788.     while (i--)
  789.     {   pline->chain = ybucket[pline->y1 - base];
  790.         ybucket[pline->y1 - base] = pline;
  791.         pline++;
  792.     }
  793. }
  794.  
  795. /* Static variables for imaging */
  796.  
  797. static int imode, incol, inproc, imulti, ifast;
  798. static int iwidth, iheight, ibps, ibpsn, ibwdth, ibshf, ismax;
  799. static int ibpos, ix1, iy1, idx, idy;
  800. static float ictm[6], icti[6];
  801.  
  802. static char *ibstring[4], ibodd[3];
  803.  
  804. static int *isample;
  805.  
  806. static struct
  807. {   float shade[4];
  808. } *ishade;
  809.  
  810. static union
  811. {   int i;
  812.     unsigned char b[4];
  813. } is;
  814.  
  815. /* Render an image */
  816.  
  817. void image(int width, int height, int bps, float *matrix, int mode,
  818.            int ncol, int multi, struct object *procs)
  819. {   struct object *token1;
  820.     struct point point;
  821.     float newctm[6], *shade;
  822.     int t0, t1, t2, t3;
  823.     int bmin, bmax, bpos, blen;
  824.     int xpos1, ypos1, xpos2, ypos2, odds;
  825.     int nest, i, lev;
  826.  
  827.     if (istate.flags & intchar)
  828.         if      (istate.type < 2)
  829.             return;
  830.         else if (istate.type == 2 && !gstate.cacheflag)
  831.             return;
  832.     if (istate.flags & intgraph)
  833.         error(errundefined);
  834.  
  835.     lev = flushlevel(-1);
  836.  
  837.     /* Set up the static variables */
  838.  
  839.     imode = mode;
  840.     incol = ncol;
  841.     inproc = multi ? ncol : 1;
  842.     imulti = multi;
  843.     iwidth = width;
  844.     iheight = height;
  845.     ibps = bps;
  846.     ibpsn = multi ? bps : bps * ncol;
  847.     ibwdth = (width * ibpsn + 7) / 8;
  848.     ibshf = (ibps == 1) ? 0 : (ibps == 2) ? 1 : (ibps == 4) ? 2 : 3;
  849.     ismax = ~(~0 << ibps);
  850.  
  851.     /* Find some memory for the sample and shade buffers */
  852.  
  853.     blen = bmax = gstate.dev.xsize * sizeof(int);
  854.     if (incol == 1) bmax += (ismax + 1) * sizeof (float [4]);
  855.     checkimagesize(bmax);
  856.     isample = memibeg;
  857.     ishade = (void *) ((char *) memibeg + blen);
  858.  
  859.     /* Set up the halftone patterns */
  860.  
  861.     if (halfok > gnest) setuphalf();
  862.  
  863.     /* For imagemask set up the halftone screens now */
  864.  
  865.     if (mode >= 0)
  866.         setupfill();
  867.  
  868.     /* Otherwise, if there is only one colour set up the shade table */
  869.  
  870.     else if (incol == 1)
  871.         for (i = 0; i <= ismax; i++)
  872.         {   shade = &ishade[i].shade[0];
  873.             shade[0] = (float) i / ismax;
  874.             mapcolour(1, shade, gstate.dev.depth, shade);
  875.             calltransfer(shade, shade);
  876.         }
  877.  
  878.     /* The transformation matrix from the image to the page is the inverse
  879.      * of the image matrix multiplied by the ctm.  Test if we can do a fast
  880.      * image (no clipping, 1 sample bit per pixel, horizontal).  Calculate
  881.      * the locations of the corners (slow image if we need to clip in the x
  882.      * direction).  For a slow image we also calculate the inverse of the
  883.      * transformation matrix; then we inverse delta transform a unit x pixel
  884.      * step to find the corresponding displacement in image space */
  885.  
  886.     invertmatrix(newctm, matrix);
  887.     multiplymatrix(ictm, newctm, gstate.ctm);
  888.     ifast = 0;
  889.     if (!gstate.clipflag && incol == 1 && ibps == 1)
  890.     {   t0 = floor(iwidth * ictm[0] + 0.5);
  891.         t1 = floor(iwidth * ictm[1] + 0.5);
  892.         t2 = floor(iheight * ictm[2] + 0.5);
  893.         t3 = floor(iheight * ictm[3] + 0.5);
  894.         if (t0 == iwidth && t1 == 0 && t2 == 0)
  895.         {   if      (t3 ==  height)
  896.                 ifast =  1;
  897.             else if (t3 == -height)
  898.                 ifast = -1;
  899.             ix1 = floor(ictm[4] + 0.5);
  900.             iy1 = floor(ictm[5] + 0.5);
  901.             if (ix1 < 0 || (ix1 + iwidth) > gstate.dev.xsize)
  902.                 ifast = 0;
  903.         }
  904.     }
  905.     if (ifast == 0)
  906.     {   invertmatrix(icti, ictm);
  907.         point.x = 1.0;
  908.         point.y = 0.0;
  909.         dtransform(&point, icti);
  910.         idx = (double) point.x * 65536.0;
  911.         idy = (double) point.y * 65536.0;
  912.     }
  913.  
  914.     /* Calculate the number of bytes we need.  Loop until we have rendered
  915.      * them all */
  916.  
  917.     bpos = bmin = 0;
  918.     blen = ibwdth * height;
  919.  
  920.     while (blen)
  921.     {
  922.         /* Call the procs whenever we run out of bytes */
  923.  
  924.         if (bmin == 0)
  925.         {   ibpos = bpos;
  926.             for (i = 0; i < inproc; i++)
  927.             {   nest = opernest;
  928.                 pushint();
  929.                 istate.flags = intgraph;
  930.                 interpret(procs + i);
  931.                 popint();
  932.                 if (opernest > nest + 1) error(errstackoverflow);
  933.                 if (opernest < nest + 1) error(errstackunderflow);
  934.                 token1 = &operstack[opernest - 1];
  935.                 if (token1->type != typestring) error(errtypecheck);
  936.                 if (token1->flags & flagrprot) error(errinvalidaccess);
  937.                 ibstring[i] = vmsptr(token1->value.vref);
  938.                 if (i == 0)
  939.                     bmin = token1->length;
  940.                 else
  941.                     if (token1->length != bmin) error(errrangecheck);
  942.                 opernest = nest;
  943.             }
  944.             if (bmin == 0) break;
  945.             if (bmin > blen) bmin = blen;
  946.         }
  947.  
  948.         /* Render the bytes we have found */
  949.  
  950.         bmax = bmin;
  951.         xpos1 = bpos % ibwdth;
  952.         ypos1 = bpos / ibwdth;
  953.  
  954.         /* Fast image */
  955.  
  956.         if (ifast != 0)
  957.             imagefast(xpos1, ypos1, bmax);
  958.  
  959.         /* Slow image.  The slow rendering routine can only handle
  960.          * rectangles, so we split into segments as necessary */
  961.  
  962.         else
  963.         {   if (xpos1 != 0)
  964.             {   if ((xpos1 + bmax) >= ibwdth)
  965.                 {   bmax = ibwdth - xpos1;
  966.                     xpos2 = ibwdth;
  967.                 }
  968.                 else
  969.                     xpos2 = xpos1 + bmax;
  970.                 ypos2 = ypos1 + 1;
  971.             }
  972.             else
  973.             {   xpos2 = (bpos + bmax) % ibwdth;
  974.                 ypos2 = (bpos + bmax) / ibwdth;
  975.                 if (ypos2 != ypos1)
  976.                 {   bmax = bmax - xpos2;
  977.                     xpos2 = ibwdth;
  978.                 }
  979.                 else
  980.                     ypos2 = ypos1 + 1;
  981.             }
  982.  
  983.             /* If we mave multiple colous and a single proc, we may have
  984.              * a partial sample left over, which we save in a buffer for
  985.              * next time.  (But ignore the extra bits at the end of a
  986.              * row.)  Adjust the x position according */
  987.  
  988.             xpos1 = (xpos1 << 3) >> ibshf;
  989.             xpos2 = (xpos2 << 3) >> ibshf;
  990.             if (ibpsn != ibps)
  991.             {   odds = xpos2 % incol;
  992.                 xpos1 /= incol;
  993.                 xpos2 /= incol;
  994.                 if (xpos2 >= iwidth)
  995.                     xpos2 = iwidth;
  996.                 else
  997.                     if (odds != 0)
  998.                     {   i = (odds * ibpsn + 7) >> 3;
  999.                         memcpy(&ibodd[3 - i], &ibstring[0][bmax - i], i);
  1000.                     }
  1001.             }
  1002.             else
  1003.                 if (xpos2 > iwidth)
  1004.                     xpos2 = iwidth;
  1005.  
  1006.             imageslow(xpos1, ypos1, xpos2, ypos2);
  1007.         }
  1008.         bpos += bmax;
  1009.         blen -= bmax;
  1010.         bmin -= bmax;
  1011.     }
  1012.  
  1013.     flushlevel(lev);
  1014. }
  1015.  
  1016. /* Image slow, like path filling but copies image data */
  1017.  
  1018. void imageslow(int xpos1, int ypos1, int xpos2, int ypos2)
  1019. {   struct point point[5], *ppoint;
  1020.     struct line *pline, **ppline;
  1021.     struct lineseg lineseg, *plineseg;
  1022.     struct halfscreen *hscreen;
  1023.     struct halftone *htone;
  1024.     char *dptr1, *dptr2;        /* device buffer pointers */
  1025.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  1026.     float shade[4];
  1027.     int flag, count, segments;  /* in-out flag, counter, segments */
  1028.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  1029.     int x1, x2, xp, xx;         /* current, previous x position range */
  1030.     int y1, y2, yy;             /* min, max, current y position */
  1031.     int cdir, fdir, sdir;       /* clip, fill direction counters */
  1032.     int poff;                   /* offset of line from page */
  1033.     int xmod, hxsize;           /* position modulo halftone screen */
  1034.     int mask1, mask2;           /* bit masks for first and last bytes */
  1035.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  1036.     int plane;
  1037.     int ix, iy, jx, jy, bx, by, ib, ii;
  1038.  
  1039.     /* Construct the outline of the area to be imaged */
  1040.  
  1041.     lineend = 0;
  1042.     ymax = ylwb = gstate.dev.ybase * 256.0;
  1043.     ymin = yupb = (gstate.dev.ybase + gstate.dev.ysize) * 256.0;
  1044.  
  1045.     point[0].x = point[3].x = xpos1;
  1046.     point[1].x = point[2].x = xpos2;
  1047.     point[0].y = point[1].y = ypos1;
  1048.     point[2].y = point[3].y = ypos2;
  1049.     point[4] = point[0];
  1050.  
  1051.     ppoint = &point[0];
  1052.     for (count = 0; count < 5 ; count++)
  1053.     {   transform(ppoint, ictm);
  1054.         if (count > 0) fillline(ppoint - 1, 0, 1);
  1055.         ppoint++;
  1056.     }
  1057.  
  1058.     /* Add the clip lines */
  1059.  
  1060.     y1 =  ((int) ymin) >> 8;
  1061.     y2 = (((int) ymax) >> 8) + 1;
  1062.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  1063.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  1064.     ylwb = ymin;
  1065.     yupb = ymax;
  1066.     count = gstate.pathbeg - gstate.clipbeg;
  1067.     ppoint = &patharray[gstate.clipbeg];
  1068.     while (count--)
  1069.     {   if (ppoint->type != ptmove) fillline(ppoint - 1, 1, 0);
  1070.         ppoint++;
  1071.     }
  1072.  
  1073.     /* Set up the y buckets */
  1074.  
  1075.     setybucket(gstate.dev.ybase, gstate.dev.ysize);
  1076.  
  1077.     /* Render the area.  Start at the lowest scan line in the path and loop
  1078.      * until we reach the highest */
  1079.  
  1080.     active = discard = sort = 0;
  1081.     poff = (y1 - gstate.dev.ybase) * gstate.dev.xbytes;
  1082.     yy = y1;
  1083.     while (yy < y2)
  1084.     {
  1085.         /* Add all the new lines */
  1086.  
  1087.         pline = ybucket[yy - gstate.dev.ybase];
  1088.         ybucket[yy - gstate.dev.ybase] = 0;
  1089.         while (pline)
  1090.         {   lineptr[active++] = pline;
  1091.             pline = pline->chain;
  1092.             sort++;
  1093.         }
  1094.  
  1095.         /* If we have any lines out of order or (new, being discarded) then
  1096.          * we Shell sort the lines according to their current x coordinates.
  1097.          * Any previously finished lines have large x coordinates so will be
  1098.          * moved to the end of the array where they are discarded */
  1099.  
  1100.         sort += discard;
  1101.         if (sort != 0)
  1102.         {   count = active;
  1103.             for (;;)
  1104.             {   count = count / 3 + 1;
  1105.                 for (x1 = count; x1 < active; x1++)
  1106.                     for (x2 = x1 - count;
  1107.                          x2 >= 0 &&
  1108.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  1109.                          x2 -= count)
  1110.                     {   pline = lineptr[x2];
  1111.                         lineptr[x2] = lineptr[x2 + count];
  1112.                         lineptr[x2 + count] = pline;
  1113.                     }
  1114.                 if (count == 1) break;
  1115.             }
  1116.             active -= discard;
  1117.             discard = sort = 0;
  1118.         }
  1119.  
  1120.         /* Scan convert the scan line.  Only the clip lines have width */
  1121.  
  1122.         count = active;
  1123.         cdir = fdir = 0;
  1124.         ppline = &lineptr[0];
  1125.         plineseg = linesegarray;
  1126.         segments = 0;
  1127.         xp = -32767;
  1128.  
  1129.         while (count--)
  1130.         {   pline = *ppline++;
  1131.             x1 = pline->xx >> 16;
  1132.  
  1133.             /* At the end of the line (or if it is horizontal), use the
  1134.              * special value of the x increment.  Flag it to be discarded */
  1135.  
  1136.             if (yy == pline->y2)
  1137.             {   pline->xx += pline->d2;
  1138.                 x2 = pline->xx >> 16;
  1139.                 pline->xx = 0x7fffffff;
  1140.                 discard++;
  1141.  
  1142.                 if (pline->cdir != 0)
  1143.                 {   if (x2 < x1)
  1144.                     {   xx = x1;
  1145.                         x1 = x2;
  1146.                         x2 = xx;
  1147.                     }
  1148.                     x2++;
  1149.                     lineseg.fdir = 0;
  1150.                     lineseg.cdir =  1;
  1151.                     lineseg.x = x1;
  1152.                     *plineseg++ = lineseg;
  1153.                     lineseg.cdir = -1;
  1154.                     lineseg.x = x2;
  1155.                     *plineseg++ = lineseg;
  1156.                     segments += 2;
  1157.                 }
  1158.             }
  1159.  
  1160.             /* At the beginning of the line, use the special values of the
  1161.              * x increment; otherwise add the gradient to its current x
  1162.              * coordinate */
  1163.  
  1164.             else
  1165.             {   if      (yy == pline->y1)
  1166.                     pline->xx += pline->d1;  /* Beginning */
  1167.                 else
  1168.                     pline->xx += pline->dx;  /* Middle */
  1169.                 x2 = pline->xx >> 16;
  1170.                 if (x2 < xp) sort++;
  1171.                 xp = x2;
  1172.  
  1173.                 if (pline->cdir != 0)
  1174.                 {   if (x2 < x1)
  1175.                     {   xx = x1;
  1176.                         x1 = x2;
  1177.                         x2 = xx;
  1178.                     }
  1179.                     x2++;
  1180.                     lineseg.fdir = 0;
  1181.                     sdir = cdir;
  1182.                     cdir += pline->cdir;
  1183.                     if      (sdir == 0)      /* Left edge */
  1184.                     {   lineseg.cdir =  2;
  1185.                         lineseg.x = x1;
  1186.                         *plineseg++ = lineseg;
  1187.                         lineseg.cdir = -1;
  1188.                         lineseg.x = x2;
  1189.                         *plineseg++ = lineseg;
  1190.                         segments += 2;
  1191.                     }
  1192.                     else if (cdir == 0)      /* Right edge */
  1193.                     {   lineseg.cdir = -1;
  1194.                         lineseg.x = x2;
  1195.                         *plineseg++ = lineseg;
  1196.                         segments += 1;
  1197.                     }
  1198.                     else if (x1 != x2)       /* Interior, draw width */
  1199.                     {   lineseg.cdir =  1;
  1200.                         lineseg.x = x1;
  1201.                         *plineseg++ = lineseg;
  1202.                         lineseg.cdir = -1;
  1203.                         lineseg.x = x2;
  1204.                         *plineseg++ = lineseg;
  1205.                         segments += 2;
  1206.                     }
  1207.                 }
  1208.                 else
  1209.                 {   lineseg.cdir = 0;
  1210.                     if (fdir == 0)           /* Left edge */
  1211.                     {   lineseg.fdir =  1;
  1212.                         lineseg.x = x1;
  1213.                         *plineseg++ = lineseg;
  1214.                         segments += 1;
  1215.                     }
  1216.                     else                     /* Right edge */
  1217.                     {   lineseg.fdir = -1;
  1218.                         lineseg.x = x1;
  1219.                         *plineseg++ = lineseg;
  1220.                         segments += 1;
  1221.                     }
  1222.                     fdir += pline->fdir;
  1223.                 }
  1224.             }
  1225.         }
  1226.  
  1227.         /* Sort the line segment list.  It should be almost in order, so
  1228.          * a simple sort is probably optimal */
  1229.  
  1230.         xx = 0;
  1231.         while (xx < segments - 1)
  1232.         {   flag = 0;
  1233.             count = segments - 1 - xx;
  1234.             plineseg = linesegarray;
  1235.             while (count--)
  1236.             {   if (plineseg->x > (plineseg + 1)->x)
  1237.                 {   flag = 1;
  1238.                     lineseg = *plineseg;
  1239.                     *plineseg = *(plineseg + 1);
  1240.                     *(plineseg + 1) = lineseg;
  1241.                 }
  1242.                 plineseg++;
  1243.             }
  1244.             if (flag == 0) break;
  1245.             xx++;
  1246.         }
  1247.  
  1248.         /* Scan the list, rendering line segments as we find them */
  1249.  
  1250.         flag = 0;
  1251.         cdir = fdir = 0;
  1252.         if (!gstate.clipflag) cdir = 1;
  1253.         for (plineseg = linesegarray; segments--; plineseg++)
  1254.         {   cdir += plineseg->cdir;
  1255.             fdir += plineseg->fdir;
  1256.             if (flag == 0)
  1257.             {   if (cdir && fdir)
  1258.                 {   flag = 1;
  1259.                     x1 = plineseg->x;
  1260.                 }
  1261.                 continue;
  1262.             }
  1263.             else
  1264.             {   if (cdir && fdir)
  1265.                     continue;
  1266.                 else
  1267.                 {   flag = 0;
  1268.                     x2 = plineseg->x;
  1269.                 }
  1270.             }
  1271.             if (x1 < 0) x1 = 0;
  1272.             if (x2 > gstate.dev.xsize) x2 = gstate.dev.xsize;
  1273.             if (x1 >= x2) continue;
  1274.  
  1275.             /* Render from x1 to x2.  Inverse transform the beginning of
  1276.              * the segment to find its location in the image string; to
  1277.              * find the remaining locations we will add the x pixel step
  1278.              * values */
  1279.  
  1280.             point[0].x = x1 + 0.5;
  1281.             point[0].y = yy + 0.5;
  1282.             transform(&point[0], icti);
  1283.             ix = point[0].x * 65536.0;
  1284.             iy = point[0].y * 65536.0;
  1285.  
  1286.             /* Unpack all the sample values for the segment.  Make sure the
  1287.              * locations are within the rectangle.  For multiple procs we
  1288.              * extract all the sample bits in parallel */
  1289.  
  1290.             for (xx = x1; xx < x2; xx++)
  1291.             {   jx = ix >> 16;
  1292.                 jy = iy >> 16;
  1293.                 if (jx < xpos1) jx = xpos1;
  1294.                 if (jx >= xpos2) jx = xpos2 - 1;
  1295.                 if (jy < ypos1) jy = ypos1;
  1296.                 if (jy >= ypos2) jy = ypos2 - 1;
  1297.                 by = jy * ibwdth - ibpos;
  1298.                 if      (incol == 1)
  1299.                 {   bx = jx << ibshf;
  1300.                     ib = by + (bx >> 3);
  1301.                     is.i = ((unsigned char *) ibstring[0])[ib];
  1302.                     if      (ibps == 1)
  1303.                         is.i = (is.i >> (~bx & 7)) & 0x01;
  1304.                     else if (ibps == 2)
  1305.                         is.i = (is.i >> (~bx & 6)) & 0x03;
  1306.                     else if (ibps == 4)
  1307.                         is.i = (bx & 4) ? is.i & 0x0f : is.i >> 4;
  1308.                 }
  1309.                 else if (incol == inproc)
  1310.                 {   bx = jx << ibshf;
  1311.                     ib = by + (bx >> 3);
  1312.                     is.b[0] = ibstring[0][ib];
  1313.                     is.b[1] = ibstring[1][ib];
  1314.                     is.b[2] = ibstring[2][ib];
  1315.                     is.b[3] = (inproc == 4) ? ibstring[3][ib]: 0;
  1316.                     if      (ibps == 1)
  1317.                         is.i = (is.i >> (~bx & 7)) & 0x01010101;
  1318.                     else if (ibps == 2)
  1319.                         is.i = (is.i >> (~bx & 6)) & 0x03030303;
  1320.                     else if (ibps == 4)
  1321.                     {   if (!(bx & 4)) is.i >>= 4;
  1322.                         is.i &= 0x0f0f0f0f;
  1323.                     }
  1324.                 }
  1325.                 else
  1326.                 {   bx = jx * ibpsn;
  1327.                     is.b[3] = 0;
  1328.                     for (plane = 0; plane < incol; plane++)
  1329.                     {   ib = by + (bx >> 3);
  1330.                         ii = (ib < 0) ?
  1331.                             ((unsigned char *) ibodd) [3 + ib] :
  1332.                             ((unsigned char *) (ibstring[0])) [ib];
  1333.                         if      (ibps == 1)
  1334.                             is.b[plane] = (ii >> (~bx & 7)) & 0x01;
  1335.                         else if (ibps == 2)
  1336.                             is.b[plane] = (ii >> (~bx & 6)) & 0x03;
  1337.                         else if (ibps == 4)
  1338.                             is.b[plane] = (bx & 4) ? ii & 0x0f : ii >> 4;
  1339.                         else
  1340.                             is.b[plane] = ii;
  1341.                         bx += ibps;
  1342.                     }
  1343.                 }
  1344.  
  1345.                 isample[xx] = is.i;
  1346.                 ix += idx;
  1347.                 iy += idy;
  1348.             }
  1349.  
  1350.             /* Render runs of pixels with the same sample value together */
  1351.  
  1352.             while (x1 < x2)
  1353.             {   is.i = isample[x1];
  1354.                 xx = x1;
  1355.                 while (xx < x2)
  1356.                 {   xx++;
  1357.                     if (isample[xx] != is.i) break;
  1358.                 }
  1359.                 xbyt1 = x1 >> 3;
  1360.                 xbyt2 = (xx - 1) >> 3;
  1361.                 mask1 =  0xff >> (x1 & 7);
  1362.                 mask2 = ~0xff >> (((xx - 1) & 7) + 1);
  1363.                 x1 = xx;
  1364.  
  1365.                 /* Imagemask, halftone screens already set up */
  1366.  
  1367.                 if      (imode >= 0)
  1368.                 {   if (is.i != imode) continue;
  1369.                 }
  1370.  
  1371.                 /* Image, only one colour, use shade table */
  1372.  
  1373.                 else if (incol == 1)
  1374.                     setupscreen(ishade[is.i].shade);
  1375.  
  1376.                 /* Image, multiple colours, no shade table */
  1377.  
  1378.                 else
  1379.                 {   shade[0] = (float) is.b[0] / ismax;
  1380.                     shade[1] = (float) is.b[1] / ismax;
  1381.                     shade[2] = (float) is.b[2] / ismax;
  1382.                     shade[3] = (float) is.b[3] / ismax;
  1383.                     mapcolour(incol, shade, gstate.dev.depth, shade);
  1384.                     calltransfer(shade, shade);
  1385.                     setupscreen(shade);
  1386.                 }
  1387.  
  1388.                 /* Loop through the bit planes */
  1389.  
  1390.                 hscreen = &halfscreen[0];
  1391.                 for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1392.                 {   htone = hscreen->halftone;
  1393.                     dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  1394.                     dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  1395.  
  1396.                     /* Optimise black or white */
  1397.  
  1398.                     if      (hscreen->num == 0)
  1399.                     {   if (dptr1 == dptr2)
  1400.                             *dptr1 |= (mask1 & mask2);
  1401.                         else
  1402.                         {   *dptr1++ |= mask1;
  1403.                             while (dptr1 != dptr2) *dptr1++ = 0xffff;
  1404.                             *dptr1 |= mask2;
  1405.                         }
  1406.                     }
  1407.                     else if (hscreen->num == htone->area)
  1408.                     {   if (dptr1 == dptr2)
  1409.                             *dptr1 &= ~(mask1 & mask2);
  1410.                         else
  1411.                         {   *dptr1++ &= ~mask1;
  1412.                             while (dptr1 != dptr2) *dptr1++ = 0x0000;
  1413.                             *dptr1 &= ~mask2;
  1414.                         }
  1415.                     }
  1416.  
  1417.                     /* The general case needs a halftone screen */
  1418.  
  1419.                     else
  1420.                     {   xmod = xbyt1 % htone->xsize;
  1421.                         hbeg = hscreen->ptr +
  1422.                             (yy % htone->ysize) * htone->xsize;
  1423.                         hptr = hbeg + xmod;
  1424.                         hxsize = htone->xsize;
  1425.                         if (dptr1 == dptr2)
  1426.                         {   mask1 &= mask2;
  1427.                             *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  1428.                         }
  1429.                         else
  1430.                         {   *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  1431.                             dptr1++;
  1432.                             hptr++;
  1433.                             for (;;)
  1434.                             {   xmod++;
  1435.                                 if (xmod == hxsize)
  1436.                                 {   xmod = 0;
  1437.                                     hptr = hbeg;
  1438.                                 }
  1439.                                 if (dptr1 == dptr2) break;
  1440.                                 *dptr1++ = *hptr++;
  1441.                             }
  1442.                             *dptr1 = (*dptr1 & ~mask2) | (*hptr & mask2);
  1443.                         }
  1444.                     }
  1445.                 }
  1446.             }
  1447.         }
  1448.  
  1449.         /* Continue with the next scan line */
  1450.  
  1451.         poff += gstate.dev.xbytes;
  1452.         yy++;
  1453.     }
  1454.  
  1455.     ybflag = 0;
  1456.     flushlpage(y1, y2);
  1457. }
  1458.  
  1459. /* Image fast */
  1460.  
  1461. void imagefast(int xpos1, int ypos1, int blen)
  1462. {   struct halfscreen *hscreen;
  1463.     struct halftone *htone;
  1464.     char *dptr1, *dptr2;        /* device buffer pointers */
  1465.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  1466.     unsigned char *bsample, *bstr;
  1467.     char *bstring;
  1468.     int bmax, x1, x2, y1, y2, yy, i;
  1469.     int xshf1, xshf2, ibyte;
  1470.     int poff;                   /* offset of line from page */
  1471.     int xmod, hxsize;           /* position modulo halftone screen */
  1472.     int mask1, mask2;           /* bit masks for first and last bytes */
  1473.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  1474.     int plane;
  1475.  
  1476.     bstring = ibstring[0];
  1477.     if (ifast > 0)
  1478.         yy = iy1 + ypos1;
  1479.     else
  1480.         yy = iy1 - ypos1 - 1;
  1481.     y1 = yy;
  1482.  
  1483.     /* Loop rendering rows */
  1484.  
  1485.     while (blen)
  1486.     {   x1 = ix1 + (xpos1 << 3);
  1487.         x2 = ix1 + iwidth;
  1488.         bmax = ibwdth - xpos1;
  1489.         if (blen < bmax)
  1490.         {   x2 = x1 + (blen << 3);
  1491.             bmax = blen;
  1492.         }
  1493.  
  1494.         /* Clip in the y direction */
  1495.  
  1496.         if (yy >= gstate.dev.ybase &&
  1497.             yy < gstate.dev.ybase + gstate.dev.ysize)
  1498.         {   poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  1499.  
  1500.             /* Bit shift the row */
  1501.  
  1502.             xshf1 = x1 & 7;
  1503.             xshf2 = ((x2 - 1) & 7) + 1;
  1504.             if (xshf1 == 0)
  1505.                 memcpy((char *) isample, bstring, bmax);
  1506.             else
  1507.             {   bstr = (unsigned char *) bstring;
  1508.                 bsample = (char *) isample;
  1509.                 i = bmax;
  1510.                 *bsample++ = *bstr++ >> xshf1;
  1511.                 while (--i)
  1512.                 {   *bsample++ = ((*(bstr - 1) << 8) | *bstr) >> xshf1;
  1513.                     bstr++;
  1514.                 }
  1515.                 *bsample = (*(bstr - 1) << 8) >> xshf1;
  1516.             }
  1517.             bsample = (char *) isample;
  1518.  
  1519.             xbyt1 = x1 >> 3;
  1520.             xbyt2 = (x2 - 1) >> 3;
  1521.             mask1 =  0xff >> xshf1;
  1522.             mask2 = ~0xff >> xshf2;
  1523.  
  1524.             /* Image all the samples that are 0 */
  1525.  
  1526.             if (imode < 0)
  1527.                 setupscreen(ishade[0].shade);
  1528.             if (imode != 1)
  1529.             {   bsample[0] |= ~mask1;
  1530.                 bsample[xbyt2 - xbyt1] |= ~mask2;
  1531.                 hscreen = &halfscreen[0];
  1532.                 for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1533.                 {   htone = hscreen->halftone;
  1534.                     dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  1535.                     dptr2 = gstate.dev.buf[plane] + poff + xbyt2 + 1;
  1536.                     bstr = bsample;
  1537.  
  1538.                     /* Optimise black or white */
  1539.  
  1540.                     if      (hscreen->num == 0)
  1541.                         for (;;)
  1542.                         {   *dptr1++ |= ~*bstr++;
  1543.                             if (dptr1 == dptr2) break;
  1544.                         }
  1545.                     else if (hscreen->num == htone->area)
  1546.                         for (;;)
  1547.                         {   *dptr1++ &=  *bstr++;
  1548.                             if (dptr1 == dptr2) break;
  1549.                         }
  1550.  
  1551.                     /* The general case needs a halftone screen */
  1552.  
  1553.                     else
  1554.                     {   xmod = xbyt1 % htone->xsize;
  1555.                         hbeg = hscreen->ptr +
  1556.                             (yy % htone->ysize) * htone->xsize;
  1557.                         hptr = hbeg + xmod;
  1558.                         hxsize = htone->xsize;
  1559.                         for (;;)
  1560.                         {   ibyte = *bstr++;
  1561.                             *dptr1 = (*dptr1 &  ibyte) | (*hptr++ & ~ibyte);
  1562.                             dptr1++;
  1563.                             if (dptr1 == dptr2) break;
  1564.                             xmod++;
  1565.                             if (xmod == hxsize)
  1566.                             {   xmod = 0;
  1567.                                 hptr = hbeg;
  1568.                             }
  1569.                         }
  1570.                     }
  1571.                 }
  1572.             }
  1573.  
  1574.             /* Image all the samples that are 1 */
  1575.  
  1576.             if (imode < 0)
  1577.                 setupscreen(ishade[1].shade);
  1578.             if (imode != 0)
  1579.             {   bsample[0] &= mask1;
  1580.                 bsample[xbyt2 - xbyt1] &= mask2;
  1581.                 hscreen = &halfscreen[0];
  1582.                 for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1583.                 {   htone = hscreen->halftone;
  1584.                     dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  1585.                     dptr2 = gstate.dev.buf[plane] + poff + xbyt2 + 1;
  1586.                     bstr = bsample;
  1587.  
  1588.                     /* Optimise black or white */
  1589.  
  1590.                     if      (hscreen->num == 0)
  1591.                         for (;;)
  1592.                         {   *dptr1++ |=  *bstr++;
  1593.                             if (dptr1 == dptr2) break;
  1594.                         }
  1595.                     else if (hscreen->num == htone->area)
  1596.                         for (;;)
  1597.                         {   *dptr1++ &= ~*bstr++;
  1598.                             if (dptr1 == dptr2) break;
  1599.                         }
  1600.  
  1601.                     /* The general case needs a halftone screen */
  1602.  
  1603.                     else
  1604.                     {   xmod = xbyt1 % htone->xsize;
  1605.                         hbeg = hscreen->ptr +
  1606.                             (yy % htone->ysize) * htone->xsize;
  1607.                         hptr = hbeg + xmod;
  1608.                         hxsize = htone->xsize;
  1609.                         for (;;)
  1610.                         {   ibyte = *bstr++;
  1611.                             *dptr1 = (*dptr1 & ~ibyte) | (*hptr++ &  ibyte);
  1612.                             dptr1++;
  1613.                             if (dptr1 == dptr2) break;
  1614.                             xmod++;
  1615.                             if (xmod == hxsize)
  1616.                             {   xmod = 0;
  1617.                                 hptr = hbeg;
  1618.                             }
  1619.                         }
  1620.                     }
  1621.                 }
  1622.             }
  1623.         }
  1624.         xpos1 = 0;
  1625.         yy += ifast;
  1626.         bstring += bmax;
  1627.         blen -= bmax;
  1628.     }
  1629.  
  1630.     if (ifast < 0)
  1631.     {   y2 = y1;
  1632.         y1 = yy;
  1633.     }
  1634.     else
  1635.         y2 = yy;
  1636.     if (y1 < gstate.dev.ybase)
  1637.         y1 = gstate.dev.ybase;
  1638.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  1639.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  1640.     flushlpage(y1, y2);
  1641. }
  1642.  
  1643. /* Erase the page */
  1644.  
  1645. void erasepage(void)
  1646. {   struct halfscreen *hscreen;
  1647.     struct halftone *htone;
  1648.     char *hbeg, *hptr, *pbuf;
  1649.     float shade[4];
  1650.     int xlen, xpos, ypos, ymod;
  1651.     int hxsize, hysize;
  1652.     int plane;
  1653.  
  1654.     if (istate.flags & intgraph) error(errundefined);
  1655.  
  1656.     /* Set up the halftone pattern if necessary */
  1657.  
  1658.     if (halfok > gnest) setuphalf();
  1659.  
  1660.     /* Set up the halftine screens for a gray level of 1.0 */
  1661.  
  1662.     shade[0] = shade[1] = shade[2] = shade[3] = 1.0;
  1663.     calltransfer(shade, shade);
  1664.     setupscreen(shade);
  1665.  
  1666.     /* Loop through the bit planes */
  1667.  
  1668.     hscreen = &halfscreen[0];
  1669.     for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1670.     {   pbuf = gstate.dev.buf[plane];
  1671.         htone = hscreen->halftone;
  1672.  
  1673.         /* Optimse erase to black or white (the commonest cases) */
  1674.  
  1675.         if      (hscreen->num == 0)
  1676.             memset(pbuf, 0xff, gstate.dev.len);
  1677.         else if (hscreen->num == htone->area)
  1678.             memset(pbuf, 0x00, gstate.dev.len);
  1679.  
  1680.         /* Otherwise we replicate the halftone screen */
  1681.  
  1682.         else
  1683.         {   hxsize = htone->xsize;
  1684.             hysize = htone->ysize;
  1685.             hbeg = hscreen->ptr;
  1686.             ymod = gstate.dev.ybase % hysize;
  1687.             hptr = hbeg + ymod * hxsize;
  1688.  
  1689.             /* Loop for all the rows */
  1690.  
  1691.             for (ypos = 0; ypos < gstate.dev.ysize; ypos++)
  1692.             {   xpos = 0;
  1693.  
  1694.                 /* Replicate the screen through the row. */
  1695.  
  1696.                 for (;;)
  1697.                 {   xlen = gstate.dev.xbytes - xpos;
  1698.                     if (xlen == 0) break;
  1699.                     if (xlen > hxsize) xlen = hxsize;
  1700.                     memcpy(pbuf, hptr, xlen);
  1701.                     pbuf += xlen;
  1702.                     xpos += xlen;
  1703.                 }
  1704.  
  1705.                 /* Step on to next row.  Restart the screen as necessary */
  1706.  
  1707.                 hptr += hxsize;
  1708.                 ymod++;
  1709.                 if (ymod == hysize)
  1710.                 {   ymod = 0;
  1711.                     hptr = hbeg;
  1712.                 }
  1713.             }
  1714.         }
  1715.     }
  1716.     flushlpage(gstate.dev.ybase, gstate.dev.ybase + gstate.dev.ysize);
  1717. }
  1718.  
  1719. /* End of file "postdraw.c" */
  1720.